Skip to content

feat: Implement htmlProcessor as the documentProcessor for HTML#734

Draft
u1f992 wants to merge 4 commits into
mainfrom
feat/#733-html-processor
Draft

feat: Implement htmlProcessor as the documentProcessor for HTML#734
u1f992 wants to merge 4 commits into
mainfrom
feat/#733-html-processor

Conversation

@u1f992
Copy link
Copy Markdown
Member

@u1f992 u1f992 commented Jan 21, 2026

closes: #733

@spring-raining spring-raining force-pushed the main branch 3 times, most recently from aa1bba6 to dea7ddf Compare February 1, 2026 01:37
@u1f992 u1f992 force-pushed the feat/#733-html-processor branch 3 times, most recently from 1561b6d to c194a2d Compare February 6, 2026 02:27
@u1f992 u1f992 force-pushed the feat/#733-html-processor branch from c194a2d to 9c531b3 Compare February 6, 2026 03:45
@u1f992 u1f992 marked this pull request as ready for review February 6, 2026 03:50
@u1f992
Copy link
Copy Markdown
Member Author

u1f992 commented Feb 6, 2026

実装は普通だと思うのですが、documentProcessorと同じバージョンのProcessorを公開するために、メイン部分と干渉する別バージョンのパッケージを別名でインストールしています。src/processor/html-processor.tsの冒頭コメントにより詳しく残してあります。

"@types/hast-v2": "npm:@types/hast@^2.0.0",

"hastscript-v7": "npm:hastscript@^7.2.0",

@u1f992
Copy link
Copy Markdown
Member Author

u1f992 commented Feb 6, 2026

examples/customize-processorを更新したところ既存のコードが型チェックを通っていなかったので修正しました。rehype-expressive-codeはunified@10に依存しているため正常に解決する方法はないのですが、同じunist@2の範囲ですし実際動いているので多分大丈夫とみてアサーションで回避しています。また0.x.yのバージョンになっており破壊的変更が入ったときに防御できないので、パッチバージョンまで固定にしました。

Copy link
Copy Markdown
Member

@spring-raining spring-raining left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビューが遅くなりすみません 🙇 こ確認ください!

Comment thread src/processor/compile.ts
content = getJsdomFromString({
html: String(vfile),
contentType: source.contentType,
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらの変更により既存のHTML processorにrehypeのパース処理が加わることになりますが、この変更はこれまでJSDOMでは読み込めていたHTMLファイルがrehypeのパースで失敗する可能性があり、ややリスクの高い変更のように思います。

vivliostyle-cliが内部でrehype processorを使用する方法の代わりに、単純な文字列として(X)HTMLを受け渡すなど、より汎用的なオプションを検討してもらえないでしょうか?

function serializeJSDOM(content: jsdom.JSDOM) {
  if (content.window.document.contentType === 'application/xhtml+xml') {
    return `${XML_DECLARATION}\n${serializeToXml(content.window.document)}`;
  } else {
    return content.serialize();
  }
}

...

content = await getJsdomFromUrlOrFile({ src: source.pathname });
if (source.htmlProcessor) {
  const processedHtml = await source.htmlProcessor(serializeJsdom(content), ...);
  content = getJsdomFromString({
    html: processedHtml,
    contentType: source.contentType,
  });
} else {
  content = await processManuscriptHtml(content, ...);
}

Copy link
Copy Markdown
Member Author

@u1f992 u1f992 Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDOMとrehypeはどちらも最終的にparse5を使用するはずなので、JSDOMでパースできてrehypeでパースできないHTMLは基本的には考えられないかと思います。XHTMLについてはそうではないのでリスクはあると思います。

htmlProcessorをシリアライズした文字列に対して実行する形にするのは、

  • documentProcessorなど既存の方式と一貫性がない
  • ユーザー側が何らかのデシリアライズ処理を用意しなければならない
  • デシリアライズ→シリアライズを合計で3回行うことになり明らかに非効率

などから避けたいです。

プラグインのために複数回のシリアライズを検討したり一貫性の問題が生じるのは、そもそも文書変形にunifiedとJSDOMの2系統が混在しているためかと思います。現在のPRの方式は、HTML処理のまず入口部分をunifiedベースに移行し、混在に対処しようとしているものです。documentProcessorと一貫性のない形なら入れる意味がないと思っています。いかがでしょうか。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すみません、性急に進めるつもりはなかったのですが、この変更には説明できなかった追加の意図があります。

しばらく文書処理部分の拡張を進めてきた結果、内部の文書処理にJSDOMを使うのはブラウザAPI互換で書ける程度のメリットしかなく、node:vmのオーバーヘッドによるパフォーマンス上の不都合が無視できないという認識に至っています。これらはすべて、rehype/hast処理としてより合理的に書くことができます。

こちらがこのPRから進めたPoCで、内部処理からJSDOMを排除したものです(Claude Codeで強引に進めたものです。PRとしては別途書き直します)。予想通り、examplesの全PDFビルドで20%近くのパフォーマンス改善が可能です。例示のための各数個の原稿ファイルで得られる改善がこの量なので、実際の書籍で原稿ファイルが増えればより大きな改善が見込めるはずです。

その足がかりとしてまずHTML入力部分のunified化を行いたいという思惑があります。マイナーバージョンアップで済む、意味が変わらないテストケースの調整だけで通せるようにしていますが、厳密に動作の互換性を見るなら次のメジャーバージョンでの対応でも問題ないと考えています。何とぞご検討いただけますか?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ご説明ありがとうございます。rehype導入の意図について理解しました。

ただ、現時点では将来的にJSDOMの使用を完全に廃止することは難しいと考えています。例えば、vivliostyle-cliでは 入力としてWeb上のリソースを指定して その内容をWebpubやEPUBとして変換する機能がありますが、この機能はJSDOMの fromURL APIにより実現しており、JSDOMを一種のクローラーとして動作させることでこの機能を実現しています。

もちろん今回対象としている処理とWeb上のリソースは全く違うものです。しかし、JSDOMを通して元データを抽象化することで (X) HTMLの処理をシンプルに保っている側面もあるため、JSDOMとrehype両方の実装を維持することはメンテナンスコストを払うだけの強いメリットがない限り難しい判断です。documentProcessor のカスタマイズの需要が不明なこと、Vivliostyle.js自体の処理時間が支配的なことを考えると、速度面のメリットだけでは採用しづらいと考えています。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すいません、今回の変更は documentProcessor の設定に限らず適用されるものなので、HTMLの入力に関しては一律で高速化されるものですね。であれば、確かに高速化の対象としてJSDOMを介さないケースを用意することは意義がありそうです。

ただ、いずれにしても (remarkを内部に持つVFMとは異なり) rehypeがHTMLのプロセッサーとしてふさわしいかは議論すべき箇所だと思うので、文字列やbufferなどの標準的なデータ以外をAPIのインターフェースとして採用するのはもう少し考えたいです。

Copy link
Copy Markdown
Member Author

@u1f992 u1f992 Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

承知しました。プロダクトとしての舵取りが必要だと思います。こちらは要検討で保留ということでお願いします。一旦draftにしておきます。

JSDOMのサブリソース追跡についてもある程度調べていて、多くのケースでは容易に代替実装できるものの、現在行われる処理のうち特にCSSのimportの追跡には追加の依存ライブラリ(具体的にはPostCSS)を使いたいところです。上のフォークにコメントを追加しておきました。
ただこの点はむしろ、JSDOMに中途半端に乗りかかるよりもVivliostyle CLIが自前で明示的に処理すべきだろうと思います。たとえば現在はimg要素のリモートリソースは収集しますがCSS内のurl()の画像は収集しません。JSDOMの都合による挙動がEPUBとして妥当なのかは疑問です。

単に私が慣れたというところは否定しないのですが、unified/unist(hast・mdast)は速度面だけでなく、

  • feat: Allow custom extensions #667 (comment) で一度検討した、マッチャーによるProcessor選択に統合できる
  • ツールが純JavaScriptで用意されているためWebや他JSランタイムでも動作できる
  • JSONへのシリアライズが考慮されており他言語との相互運用も現実的
    • unifiedの作者はRustでMarkdownやMDXの再実装を行なっていますが、unistの仕様はこちらでも引き続き使用されています

など利点があります。また@ napi-rs/canvasに限らずネイティブコード依存は根本的な対処が難しい問題(例: #697 )を発生させることも考慮の材料になるのではと思います。
よろしくご検討ください。

Comment thread src/config/schema.ts Outdated
@u1f992 u1f992 marked this pull request as draft March 9, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Implement htmlProcessor as the documentProcessor for HTML

2 participants